package com.money.tracker.generator.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.money.tracker.auth.service.transfer.SysTransferService;
import com.money.tracker.common.constant.MoneyTrackerConstant;
import com.money.tracker.common.enums.IResponseEnum;
import com.money.tracker.common.exception.MoneyTrackerBizException;
import com.money.tracker.common.utils.StreamUtil;
import com.money.tracker.generator.entity.GenTable;
import com.money.tracker.generator.entity.GenTableColumn;
import com.money.tracker.generator.entity.req.GenTableReq;
import com.money.tracker.generator.entity.rsp.GenTableRsp;
import com.money.tracker.generator.mapper.GenTableMapper;
import com.money.tracker.generator.service.IGenTableColumnService;
import com.money.tracker.generator.service.IGenTableService;
import com.money.tracker.generator.utils.DataSourceHelper;
import com.money.tracker.generator.utils.VelocityHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.StringWriter;
import java.util.*;

/**
 * <p>
 * 代码生成业务表 服务实现类
 * </p>
 *
 * @author zhangshuai
 * @since 2024-10-08
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Lazy))
public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> implements IGenTableService {
    private final DataSourceHelper dataSourceHelper;
    private final IGenTableColumnService genTableColumnService;
    private final SysTransferService sysTransferService;
    private final GenTableServiceImpl genTableService;
    private final VelocityHelper velocityHelper;

    @Override
    public void importTable(String tables) {
        String[] tableNames = Convert.toStrArray(tables);
        // 获取所有表，数据库中表不可能很多，所以一次性查询出来放入内存处理
        List<TableInfo> tableInfos = StreamUtil.filter(dataSourceHelper.tableList(), tableInfo -> Arrays.stream(tableNames)
                .allMatch(tableName -> StringUtils.equalsIgnoreCase(tableInfo.getName(), tableName)));
        for (TableInfo tableInfo : tableInfos) {
            GenTable genTable = sysTransferService.buildGenTable(tableInfo);
            boolean saved = this.save(genTable);
            if (!saved) {
                continue;
            }
            // 获取column
            List<GenTableColumn> saveColumns = StreamUtil.toList(tableInfo.getFields(), columnInfo ->
                    sysTransferService.buildGenTableColumn(genTable, columnInfo));
            genTableColumnService.saveBatch(saveColumns);
        }
    }

    @Override
    public Page<GenTableRsp> pageTableList(GenTableReq req) {
        LambdaQueryWrapper<GenTable> queryWrapper = new LambdaQueryWrapper<>();
        // 根据表名查询
        if (StringUtils.isNotBlank(req.getTableName())) {
            queryWrapper.like(GenTable::getTableName, req.getTableName());
        }
        // 根据表描述查询
        if (StringUtils.isNotBlank(req.getTableComment())) {
            queryWrapper.like(GenTable::getTableComment, req.getTableComment());
        }
        // 根据创建时间
        if (Objects.nonNull(req.getCreateTime())) {
            queryWrapper.ge(GenTable::getCreateTime, req.getCreateTime());
        }
        // 根据修改时间
        if (Objects.nonNull(req.getUpdateTime())) {
            queryWrapper.le(GenTable::getUpdateTime, req.getUpdateTime());
        }
        Page<GenTable> genTablePage = this.page(new Page<>(req.getPageNum(), req.getPageSize()), queryWrapper);
        List<GenTableRsp> genTableRsps = StreamUtil.toList(genTablePage.getRecords(), genTable -> {
            GenTableRsp genTableRsp = new GenTableRsp();
            BeanUtils.copyProperties(genTable, genTableRsp);
            genTableRsp.setId(String.valueOf(genTable.getId()));
            return genTableRsp;
        });
        Page<GenTableRsp> result = new Page<>(genTablePage.getCurrent(), genTablePage.getPages(), genTablePage.getTotal());
        result.setRecords(genTableRsps);
        return result;
    }

    @Override
    public Page<GenTableRsp> dbPageList(GenTableReq req) {
        // 获取所有表，数据库中表不可能很多，所以一次性查询出来放入内存处理
        List<TableInfo> infoList = dataSourceHelper.tableList();
        List<TableInfo> tableInfos = StreamUtil.filter(infoList, tableInfo -> {
            if (StringUtils.isNotBlank(req.getTableName())) {
                return StringUtils.equalsIgnoreCase(tableInfo.getName(), req.getTableName());
            }
            if (StringUtils.isNotBlank(req.getTableComment())) {
                return StringUtils.equalsIgnoreCase(tableInfo.getComment(), req.getTableComment());
            }
            return true;
        });
        // 计算分页参数
        int startIndex = (req.getPageNum() - 1) * req.getPageSize();
        int endIndex = Math.min(startIndex + req.getPageSize(), tableInfos.size());
        List<GenTableRsp> tableInfoList = StreamUtil.toList(tableInfos.subList(startIndex, endIndex), tableInfo -> GenTableRsp.builder()
                .tableName(tableInfo.getName())
                .tableComment(tableInfo.getComment())
                .className(tableInfo.getEntityName())
                .build());
        Page<GenTableRsp> genTablePage = new Page<>(req.getPageNum(), req.getPageSize());
        genTablePage.setRecords(tableInfoList);
        genTablePage.setTotal(infoList.size());
        return genTablePage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long tableId) {
        this.removeById(tableId);
        genTableColumnService.remove(new LambdaQueryWrapper<GenTableColumn>()
                .eq(GenTableColumn::getTableId, tableId));
    }

    @Override
    public GenTableRsp getInfo(String tableId) {
        return GenTableRsp.builder()
                .info(this.getById(tableId))
                .columns(genTableColumnService.list(new LambdaQueryWrapper<GenTableColumn>()
                        .eq(GenTableColumn::getTableId, tableId)
                        .orderByAsc(GenTableColumn::getSort)))
                .tables(this.list())
                .build();
    }

    @Override
    public void syncDb(Long tableId) {
        // 查询数据库当中已存在的记录
        GenTable genTable = this.getById(tableId);
        if (Objects.isNull(genTable)) {
            log.error("当前id{}无法查询出表记录", tableId);
            throw new MoneyTrackerBizException(IResponseEnum.DATA_NOT_EXIST);
        }
        TableInfo tableInfo = StreamUtil.findFirst(dataSourceHelper.tableList(), table -> StringUtils.equalsIgnoreCase(table.getName(), genTable.getTableName()));
        if (Objects.isNull(tableInfo)) {
            log.error("当前表结构在数据库中已被删除");
            throw new MoneyTrackerBizException(IResponseEnum.DATA_NOT_EXIST);
        }

        GenTable newGenTable = sysTransferService.buildGenTable(tableInfo);
        newGenTable.setId(tableId);
        // 获取column
        List<GenTableColumn> newColumns = StreamUtil.toList(tableInfo.getFields(), columnInfo ->
                sysTransferService.buildGenTableColumn(genTable, columnInfo));
        // 自我代理事务,genTable修改，column先删后增
        genTableService.update(newGenTable, newColumns);
    }

    @Override
    public Map<String, String> preview(String tableId) {
        Map<String, String> dataMap = new HashMap<>();
        GenTable table = this.getById(tableId);
        if (Objects.isNull(table)) {
            log.error("当前id{}无法查询出表记录", tableId);
            throw new MoneyTrackerBizException(IResponseEnum.DATA_NOT_EXIST);
        }
        List<GenTableColumn> genTableColumns = genTableColumnService.list(new LambdaQueryWrapper<GenTableColumn>().eq(GenTableColumn::getTableId, tableId));
        VelocityContext context = velocityHelper.prepareContext(table, genTableColumns);
        // 获取模板列表
        List<String> templates = velocityHelper.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, MoneyTrackerConstant.UTF8);
            tpl.merge(context, sw);
            dataMap.put(template, sw.toString());
        }
        return dataMap;
    }

    /**
     *
     * 修改保存代码生成业务
     *
     * @param newGenTable
     * @param newColumns
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(GenTable newGenTable, List<GenTableColumn> newColumns) {
        genTableService.saveOrUpdate(newGenTable);
        genTableColumnService.remove(new LambdaQueryWrapper<GenTableColumn>()
                .eq(GenTableColumn::getTableId, newGenTable.getId()));
        genTableColumnService.saveBatch(newColumns);
    }


}
